﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace msgtypebuilder
{
    public partial class MsgTypeBuilder : Form
    {
        #region private variables
        TreeNode prev_sel = null;

        Dictionary<string, TreeNode> list_to_node = new Dictionary<string, TreeNode>();
        #endregion

        public MsgTypeBuilder()
        {
            InitializeComponent();
        }

        private bool IsExists(TreeNode node, string name)
        {
            if (node.Text == name)
                return true;

            if (node.Nodes.Count > 0)
            {
                foreach (TreeNode child in node.Nodes)
                {
                    if (IsExists(child, name))
                        return true;
                }
            }
            return false;
        }

        private bool IsExists(string name)
        {
            foreach (TreeNode node in msg_list.Nodes)
            {
                if (IsExists(node, name))
                    return true;
            }

            return false;
        }

        private void AddMsg(string name)
        {
            TreeNode tn = msg_list.SelectedNode;
            if (tn == null)
                return;

            if (name.Trim().Length < name.Length || name.Equals(string.Empty))
            {
                System.Windows.Forms.MessageBox.Show("Message Type Cant Not Contains A Blank Character!");
                return;
            }

            string msg_head = GetMessageHead(tn);

            string content = msg_head + name;
            if (!IsExists(name))
            {
                all_msg.Items.Add(content);

                TreeNode new_node = tn.Nodes.Add(name);
                tn.Expand();

                list_to_node.Add(content, new_node);
                msg_list.SelectedNode = new_node;

                RefreshCount();
            }
            else
                System.Windows.Forms.MessageBox.Show(string.Format("Message Type Already Exists!"));
        }

        private void add_msg_Click(object sender, EventArgs e)
        {
            AddMsg(msg_name.Text);
            msg_name.Text = string.Empty;
            msg_name.Focus();
        }

        private void DeleteTreeNode()
        {
            TreeNode tn = msg_list.SelectedNode;
            if (tn == null)
                return;

            if (tn.Parent != null)
            {
                string content = GetTags(tn) + GetMessageHead(tn.Parent) + tn.Text;
                msg_list.SelectedNode = tn.PrevNode;
                all_msg.Items.Remove(content);
                list_to_node.Remove(content);
                tn.Parent.Nodes.Remove(tn);

                RefreshCount();
            }
        }

        private void delete_msg_Click(object sender, EventArgs e)
        {
            DeleteTreeNode();
        }

        private void DoInit()
        {
            this.msg_list.Nodes.Clear();
            all_msg.Items.Clear();
            list_to_node.Clear();


            RefreshCount();
            msg_list.Sort();
        }

        private void new_list_Click(object sender, EventArgs e)
        {
            DoInit();
        }

        private void ReadFile(string fileName)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(fileName);
                XmlNode root = doc.SelectSingleNode("MessageType");

                foreach (XmlNode elem in root.ChildNodes)
                {
                    TreeNode type_node = this.msg_list.Nodes.Add(elem.Name, elem.Name);
                    string msg_content = GetTags(type_node) + GetMessageHead(null) + type_node.Text;
                    all_msg.Items.Add(msg_content);
                    list_to_node.Add(msg_content, type_node);
                    foreach (XmlNode child in elem)
                    {
                        TreeNode new_node = type_node.Nodes.Add(child.Name);
                        string content = GetTags(new_node) + GetMessageHead(type_node) + child.Name;
                        all_msg.Items.Add(content);
                        list_to_node.Add(content, new_node);
                    }
                }
            }
            catch(Exception e)
            {
                System.Windows.Forms.MessageBox.Show(string.Format("Open File Error:{0}", e.Message));
            }
        }

        private void open_list_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.InitialDirectory = ".\\";
            ofd.Filter = "Message Types File(*.xml)|*.xml";
            ofd.RestoreDirectory = true;
            ofd.FilterIndex = 1;
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                DoInit();
                ReadFile(ofd.FileName);
                RefreshCount();
            }
        }

        private void SaveFile(string fileName)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                XmlElement root = doc.CreateElement("MessageType");
                doc.AppendChild(root);

                foreach (TreeNode tn in msg_list.Nodes)
                {
                    XmlElement elem = doc.CreateElement(tn.Text);
                    root.AppendChild(elem);
                    foreach (TreeNode child in tn.Nodes)
                    {
                        XmlElement child_elem = doc.CreateElement(child.Text);
                        elem.AppendChild(child_elem);
                    }
                }

                doc.Save(fileName);
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show(string.Format("Save File Error:{0}", e.Message));
            }
        }

        private void save_list_Click(object sender, EventArgs e)
        {
            SaveFileDialog ofd = new SaveFileDialog();
            ofd.InitialDirectory = ".\\";
            ofd.Filter = "Message Types File(*.xml)|*.xml";
            ofd.RestoreDirectory = true;
            ofd.FilterIndex = 1;
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                SaveFile(ofd.FileName);
            }
        }

        private void MsgTypeBuilder_Load(object sender, EventArgs e)
        {
            DoInit();
        }

        private string GetTags(TreeNode node)
        {
            string tags = string.Empty;

            if (MessageHandlerBuilder.CheckRecviever(node))
                tags = "  R+";

            if (MessageHandlerBuilder.CheckSender(node))
                tags = "S+" + tags;

            if (!tags.Equals(string.Empty))
            {
                tags = "◆" + tags + "  ";
            }

            return tags;
        }

        private string GetMessageHead(TreeNode node)
        {
            string head = string.Empty;

            if (node != null)
                head = string.Format("{0}_Msg_", node.Text);
            else
                head = string.Format("NetMessage_Msg_");

            return head;
        }

        private void generate_msg_Click(object sender, EventArgs e)
        {
            MessageHandlerBuilder.GenerateMessageTypes(msg_list.Nodes);
            MessageBox.Show("Generate Message Types Success!");
        }

        private void SelectTreeNode(TreeNode node)
        {
            if (prev_sel != null)
                prev_sel.ForeColor = Color.Black;

            node.ForeColor = Color.Red;
            prev_sel = node;

            string head = GetTags(node);
            head += GetMessageHead(node.Parent);
            string content = head + node.Text;
            int index = all_msg.FindStringExact(content);
            if (index == -1)
                return;

            all_msg.SelectedIndex = index;
        }

        private void msg_list_AfterSelect(object sender, TreeViewEventArgs e)
        {
            SelectTreeNode(e.Node);
        }

        private void OnTextKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                AddMsg(msg_name.Text);
                msg_name.Text = string.Empty;
                msg_name.Focus();
            }
        }

        private void search_msg_Click(object sender, EventArgs e)
        {
            if (search_name.Text == string.Empty)
                return;

            int index = 0;
            if (all_msg.SelectedItem != null)
                index = all_msg.SelectedIndex + 1;

            for (int i = index; i < all_msg.Items.Count; ++i)
            {
                string full_name = all_msg.Items[i] as string;
                if (full_name.IndexOf(search_name.Text) != -1)
                {
                    all_msg.SelectedIndex = i;
                    break;
                }
            }
        }

        private void delete_command_Click(object sender, EventArgs e)
        {
            DeleteTreeNode();
        }

        private void rename_command_Click(object sender, EventArgs e)
        {
            Rename();
        }

        private void tree_command_Opened(object sender, EventArgs e)
        {
            TreeNode tn = msg_list.SelectedNode;
            if (tn == null || tn.Parent != null)
                tree_command.Hide();
        }

        private void node_add_Click(object sender, EventArgs e)
        {
            TreeNode tn = msg_list.SelectedNode;
            if (tn == null)
                return;

            name new_msg = new name();
            if (new_msg.ShowDialog() == DialogResult.OK)
            {
                AddMsg(new_msg.new_name);
            }
        }

        private void RenameCallback(TreeNode node, string old_name)
        {
            MessageHandlerBuilder.RenameCallback(node, old_name);
        }

        private void RenameProcess(TreeNode node, string new_name)
        {
            string head = GetTags(node) + GetMessageHead(node.Parent);
            string content = head + node.Text;
            string new_content = head + new_name;

            int index = all_msg.FindString(content);
            if (index == -1)
                return;

            RenameCallback(node, new_name);
            node.Text = new_name;
            list_to_node.Remove(content);
            list_to_node.Add(new_content, node);
            all_msg.Items[index] = new_content;
            all_msg.SelectedIndex = index;
            all_msg.Sorted = false;
            all_msg.Sorted = true;
        }

        private void Rename()
        {
            TreeNode tn = msg_list.SelectedNode;
            if (tn == null || tn.Parent == null)
                return;

            name rename = new name();
            rename.old_name = tn.Text;
            if (rename.ShowDialog() == DialogResult.OK)
            {
                if (rename.new_name != string.Empty)
                {
                    RenameProcess(tn, rename.new_name);
                }
            }
        }

        private void node_rename_Click(object sender, EventArgs e)
        {
            Rename();
        }

        private void node_delete_Click(object sender, EventArgs e)
        {
            DeleteTreeNode();
        }

        private void all_msg_SelectedIndexChanged(object sender, EventArgs e)
        {
            string list_name = all_msg.SelectedItem as string;
            if (list_name == null)
                return;

            TreeNode node = list_to_node[list_name];
            if (msg_list.SelectedNode != node)
                msg_list.SelectedNode = node;
        }

        private void RefreshCount()
        {
            msg_count.Text = string.Format("count:{0}", all_msg.Items.Count);
        }

        private void RefreshList(TreeNode node, string old_name)
        {
            string new_content = GetTags(node) + GetMessageHead(node.Parent) + node.Text;

            int index = all_msg.FindString(old_name);
            if (index == -1)
                return;

            list_to_node.Remove(old_name);
            list_to_node.Add(new_content, node);
            all_msg.Items[index] = new_content;
            all_msg.SelectedIndex = index;
            all_msg.Sorted = false;
            all_msg.Sorted = true;
        }

        private void AddCallback(TreeNode node)
        {
            HandlerBuilder hb = new HandlerBuilder();
            hb.MessageNode = node;
            string old_name = GetTags(node) + GetMessageHead(node.Parent) + node.Text;
            hb.ShowDialog();
            RefreshList(node, old_name);
        }

        private void msg_list_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node != null)
                AddCallback(e.Node);
        }

        private void node_callback_Click(object sender, EventArgs e)
        {
            if (msg_list.SelectedNode != null)
                AddCallback(msg_list.SelectedNode);
        }

        private void all_msg_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (all_msg.SelectedItem == null)
                return;

            TreeNode node;
            if (list_to_node.TryGetValue((string)(all_msg.SelectedItem), out node))
                AddCallback(node);
        }

        private void callbackToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (all_msg.SelectedItem == null)
                return;

            TreeNode node;
            if (list_to_node.TryGetValue((string)(all_msg.SelectedItem), out node))
                AddCallback(node);
        }

        private void add_root_Click(object sender, EventArgs e)
        {
            name newname = new name();
            newname.old_name = string.Empty;
            if (newname.ShowDialog() == DialogResult.OK)
            {
                if (newname.new_name != string.Empty)
                {
                    TreeNode type_node = this.msg_list.Nodes.Add(newname.new_name, newname.new_name);
                    string msg_content = GetTags(type_node) + GetMessageHead(null) + type_node.Text;
                    all_msg.Items.Add(msg_content);
                    list_to_node.Add(msg_content, type_node);
                }
                else
                    MessageBox.Show("name of the root node should not be the empty!");
            }
        }
    }
}
